package cn.tedu.mall.seckill.timer.job;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.pojo.seckill.model.SeckillSku;
import cn.tedu.mall.pojo.seckill.model.SeckillSpu;
import cn.tedu.mall.seckill.mapper.SeckillSkuMapper;
import cn.tedu.mall.seckill.mapper.SeckillSpuMapper;
import cn.tedu.mall.seckill.utils.SeckillCacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.RandomUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
public class SeckillInitialJob implements Job {

    //查询spu
    @Autowired
    private SeckillSpuMapper seckillSpuMapper;

    //根据spuId查询sku，获取库存数
    @Autowired
    private SeckillSkuMapper seckillSkuMapper;

    //适合处理频繁的更新操作，不需要将数据转换成二进制，可以减少数据类型的转换
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //更适用于查询操作，因为二进制的时候读的快，用它来去缓存随机码，因为随机码不会发生改变
    @Autowired
    private RedisTemplate redisTemplate;




    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        //缓存预热，业务需要设计在秒杀活动开始前五分钟
        LocalDateTime time = LocalDateTime.now().plusMinutes(5);//获取五分钟后的时间   如果现在是20：11     20：17  ，实际上time：20：18
        //根据time去查询商品（活动）
        List<SeckillSpu> seckillSpus = seckillSpuMapper.findSeckillSpusByTime(time);
        if (seckillSpus==null || seckillSpus.size()==0){
            log.info("还未到预热时间");
            return;
        }
        //开始预热
        //需要遍历seckillSpus集合
        for (SeckillSpu seckillSpu : seckillSpus) {
            Long spuId = seckillSpu.getSpuId();
            List<SeckillSku> seckillSkus = seckillSkuMapper.findSeckillSkusBySpuId(spuId);
            //判断seckillSkus是否为null
            if (seckillSkus==null || seckillSkus.size()==0){
                throw new CoolSharkServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"seckillSkus不能为空");
            }
            //遍历seckillSkus集合，来获取库存数
            for (SeckillSku seckillSku : seckillSkus) {
                Long skuId = seckillSku.getSkuId();
                log.info("开始为{}号商品进行缓存预热",skuId);
                //返回的格式：mall:seckill:sku:stock:1
                //根据skuId获取redis中对应的key
                String stockKey = SeckillCacheUtils.getStockKey(skuId);
                if (stringRedisTemplate.hasKey(stockKey)){
                    //如果redis中存在
                    log.info("当前{}号商品已经缓存到redis中",skuId);
                }else {
                    //如果redis中不存在,则进行缓存
                    stringRedisTemplate.boundValueOps(stockKey).set(seckillSku.getSeckillStock()+"",2*60*60+ RandomUtils.nextInt(100), TimeUnit.SECONDS);
                    log.info("成功为{}号商品添加了库存数",skuId);
                }

            }
            //生成随机码进行缓存预热
            //获取随机码的key
            String randCodeKey = SeckillCacheUtils.getRandCodeKey(spuId);
            //判断随机码是否存在
            if (redisTemplate.hasKey(randCodeKey)) {
                //如果存在，就取出随机码进行测试，实际开发是不需要这一步操作
                int randCode = (int) redisTemplate.boundValueOps(randCodeKey).get();
                log.info("spuId为{}的商品的随机码是:{}",spuId,randCode);
            }else {
                //如果没有随机码，则生成一个随机码到redis中
                int randCode = RandomUtils.nextInt(900000) + 100000;
                redisTemplate.boundValueOps(randCodeKey).set(
                        randCode,
                        2*60*60+RandomUtils.nextInt(100),
                        TimeUnit.SECONDS
                );
                log.info("成功为spuId为{}号的商品缓存随机码，随机码为：{}",spuId,randCode);
            }
        }


    }
}
